package com.zhixing.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zhixing.common.domain.dto.LocationDTO;
import com.zhixing.common.domain.dto.RoutePlanningDTO;
import com.zhixing.common.domain.entity.CouponUseInfo;
import com.zhixing.common.domain.entity.DriverInfo;
import com.zhixing.common.domain.entity.UserInfo;
import com.zhixing.common.domain.enums.CouponType;
import com.zhixing.common.domain.enums.DriverStatus;
import com.zhixing.common.domain.enums.Role;
import com.zhixing.common.domain.vo.DriverDistanceVO;
import com.zhixing.common.domain.vo.DriverInfoVO;
import com.zhixing.common.domain.vo.RoutePlanningVO;
import com.zhixing.common.exception.ZhixingException;
import com.zhixing.common.utils.LocationUtil;
import com.zhixing.common.utils.Res;
import com.zhixing.common.utils.UserContext;
import com.zhixing.map.client.MapClient;
import com.zhixing.order.domain.dto.CommissionRuleDTO;
import com.zhixing.order.domain.dto.FeeRuleDTO;
import com.zhixing.order.domain.dto.OrderGrabInfoDTO;
import com.zhixing.order.domain.dto.OrderLocationDTO;
import com.zhixing.order.domain.entity.*;
import com.zhixing.order.domain.enums.OrderStatus;
import com.zhixing.order.domain.vo.*;
import com.zhixing.order.mapper.CommissionRuleMapper;
import com.zhixing.order.mapper.FeeRuleMapper;
import com.zhixing.order.mapper.OrderMapper;
import com.zhixing.order.service.OrderService;
import com.zhixing.pay.client.PayClient;
import com.zhixing.reward.RewardClient;
import com.zhixing.user.client.UserClient;
import lombok.RequiredArgsConstructor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.retrytopic.RetryTopicHeaders;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.*;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.transaction.annotation.Transactional;
import static com.zhixing.common.constant.Constant.*;
import static com.zhixing.common.domain.enums.HttpStatus.*;

@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final KieContainer kieContainer;
    private final MapClient mapClient;
    private final UserClient userClient;
    private final RewardClient rewardclient;
    private final PayClient payClient;
    private final OrderMapper orderMapper;
    private final KafkaTemplate<String, Object> kafkaTemplate;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ThreadPoolExecutor threadPoolExecutor;
    private final RedissonClient redissonClient;
    private final FeeRuleMapper feeRuleMapper;
    private final CommissionRuleMapper commissionRuleMapper;

    public FeeRuleVO getFeeRule(FeeRuleDTO feeRuleDTO) {
        // 执行drools费用规则
        KieSession kieSession = kieContainer.newKieSession();
        FeeRuleVO feeRuleVO = new FeeRuleVO();
        kieSession.setGlobal("feeRuleVO", feeRuleVO);
        kieSession.insert(feeRuleDTO);
        kieSession.fireAllRules();
        kieSession.dispose();
        return feeRuleVO;
    }

    public CommissionRuleVO getCommissionRule(CommissionRuleDTO commissionRuleDTO) {
        // 执行drools抽成规则
        KieSession kieSession = kieContainer.newKieSession();
        CommissionRuleVO commissionRuleVO = new CommissionRuleVO();
        kieSession.setGlobal("commissionRuleVO", commissionRuleVO);
        kieSession.insert(commissionRuleDTO);
        kieSession.fireAllRules();
        kieSession.dispose();
        return commissionRuleVO;
    }

    @Override
    public OrderEstimateInfoVO estimateOrderInfo(RoutePlanningDTO routePlanningDTO) {
        // 调用地图服务路线规划
        RoutePlanningVO routePlanningVO = mapClient.routePlanning(routePlanningDTO).getData();

        // 执行drools费用规则
        BigDecimal distance = routePlanningVO.getDistance().setScale(1, RoundingMode.HALF_UP);
        FeeRuleVO feeRuleVO = getFeeRule(new FeeRuleDTO(LocalTime.now(), distance));
        return new OrderEstimateInfoVO(routePlanningVO.getPolyline(), distance, routePlanningVO.getDuration(), feeRuleVO.getTotalFee());
    }

    @Override
    public Long submitOrder(Integer userId, OrderLocationDTO orderLocationDTO) {
        // 预估订单信息
        OrderEstimateInfoVO orderEstimateInfoVO = estimateOrderInfo(BeanUtil.copyProperties(orderLocationDTO, RoutePlanningDTO.class));

        // 创建订单
        Order order = Order.builder().orderNumber(System.currentTimeMillis() + orderLocationDTO.getPhone().substring(orderLocationDTO.getPhone().length() - 4))
                .userId(userId).orderStatus(OrderStatus.WAIT).submitTime(LocalDateTime.now()).build();
        BeanUtil.copyProperties(orderLocationDTO, order);
        BeanUtil.copyProperties(orderEstimateInfoVO, order);
        orderMapper.insert(order);

        // 下单事件，派单操作，超时取消订单
        redisTemplate.opsForValue().set(ZHIXING_SUBMIT_ORDER + order.getId(), OrderStatus.WAIT.getValue(), OVERTIME_MILLISECONDS, TimeUnit.MILLISECONDS);
        ProducerRecord<String, Object> producerRecord = new ProducerRecord<>(ZHIXING_ORDER_SUBMIT, order.getId());
        producerRecord.headers().add(RetryTopicHeaders.DEFAULT_HEADER_ATTEMPTS, ByteBuffer.allocate(Integer.BYTES).putInt(1).array());
        kafkaTemplate.send(producerRecord);
        return order.getId();
    }

    @Override
    public void cancelOrder(Long orderId) {
        // 删除订单缓存，更新订单状态
        redisTemplate.delete(ZHIXING_SUBMIT_ORDER + orderId);
        LambdaUpdateWrapper<Order> luw = new LambdaUpdateWrapper<Order>().eq(Order::getId, orderId)
                .eq(Order::getOrderStatus, OrderStatus.WAIT).set(Order::getOrderStatus, OrderStatus.CANCEL);
        if (orderMapper.update(luw) == 0) throw new ZhixingException(ORDER_STATUS_ERROR);
    }

    @Override
    public void dispatchOrder(OrderSendInfo orderSendInfo) {
        threadPoolExecutor.execute(() -> {
            // 获取订单附近的司机，并发送订单给司机
            UserContext.setUserInfo(new UserInfo(orderSendInfo.getUserId(), Role.PASSENGER));
            LocationDTO locationDTO = new LocationDTO(orderSendInfo.getCityCode(), orderSendInfo.getStartLongitude(), orderSendInfo.getStartLatitude());
            List<DriverDistanceVO> driverDistanceVOList = mapClient.getOrderNearbyDrivers(locationDTO).getData();
            if (CollUtil.isEmpty(driverDistanceVOList)) return;
            List<Integer> driverIds = driverDistanceVOList.stream().map(DriverDistanceVO::getDriverId).toList();
            List<Integer> orderCountList = orderMapper.getDriverOrderCount(driverIds, LocalDate.now(), OrderStatus.COMPLETE);
            List<String> instanceIds = redisTemplate.opsForHash().multiGet(ZHIXING_DRIVER_WEBSOCKET, driverIds.stream().map(i -> (Object) i).toList()).stream().map(o -> (String) o).toList();
            for (int i = 0; i < driverDistanceVOList.size(); i++) {
                if (ObjectUtil.isEmpty(instanceIds.get(i))) continue;
                OrderGrabInfoVO orderGrabInfoVO = BeanUtil.copyProperties(orderSendInfo, OrderGrabInfoVO.class);
                BeanUtil.copyProperties(driverDistanceVOList.get(i), orderGrabInfoVO);
                CommissionRuleVO commissionRuleVO = getCommissionRule(new CommissionRuleDTO(LocalTime.now(), orderSendInfo.getEstimateDistance(), orderCountList.get(i)));
                orderGrabInfoVO.setEstimateIncome(orderSendInfo.getEstimateFee().multiply(new BigDecimal(1).subtract(commissionRuleVO.getTotalCommission())).setScale(2, RoundingMode.HALF_UP));
                if (instanceIds.get(i) != null) kafkaTemplate.send(ZHIXING_SEND_DRIVER + instanceIds.get(i), orderGrabInfoVO);
            }
        });
    }

    @Override
    public void grabOrder(OrderGrabInfoDTO orderGrabInfoDTO) {
        // 使用redisson分布式锁处理高并发司机抢单
        String key = ZHIXING_SUBMIT_ORDER + orderGrabInfoDTO.getId();
        if (!redisTemplate.hasKey(key)) throw new ZhixingException(GRAB_ORDER_FAIL);
        RLock lock = redissonClient.getLock(ZHIXING_REDISSON_ORDER + orderGrabInfoDTO.getId());
        try {
            boolean flag = lock.tryLock(WAIT_TIME_MILLISECONDS, LEASE_TIME_MILLISECONDS, TimeUnit.MILLISECONDS);
            if (!flag || !redisTemplate.hasKey(key)) throw new ZhixingException(GRAB_ORDER_FAIL);
            LambdaUpdateWrapper<Order> luw = new LambdaUpdateWrapper<Order>().eq(Order::getId, orderGrabInfoDTO.getId())
                    .eq(Order::getOrderStatus, OrderStatus.WAIT).set(Order::getDriverId, orderGrabInfoDTO.getDriverId())
                    .set(Order::getEstimateIncome, orderGrabInfoDTO.getEstimateIncome())
                    .set(Order::getOrderStatus, OrderStatus.RECEIVE).set(Order::getReceiveTime, LocalDateTime.now());
            if (orderMapper.update(luw) == 0) throw new ZhixingException(GRAB_ORDER_FAIL);
            if (!redisTemplate.delete(key)) kafkaTemplate.send(ZHIXING_ORDER_DELETE_FAIL, orderGrabInfoDTO.getId());
            String instanceId = (String) redisTemplate.opsForHash().get(ZHIXING_ORDER_WEBSOCKET, orderGrabInfoDTO.getId());
            if (instanceId != null) kafkaTemplate.send(ZHIXING_SEND_PASSENGER + instanceId, new OrderStatusVO(orderGrabInfoDTO.getId(), OrderStatus.RECEIVE));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();  // 恢复中断状态
        } finally {
            if (lock.isHeldByCurrentThread()) lock.unlock();
        }
    }

    @Override
    public DriverReceiveOrderVO driverGetReceiveOrderInfo(Long orderId) {
        // 数据库获取接单信息，缓存获取司机位置信息
        OrderReceiveInfo orderReceiveInfo = orderMapper.getReceiveOrderInfo(orderId);
        List<Point> position = redisTemplate.opsForGeo().position(ZHIXING_DRIVER_LOCATION + orderReceiveInfo.getCityCode(),
                new DriverInfo(orderReceiveInfo.getDriverId(), DriverStatus.IDLE), new DriverInfo(orderReceiveInfo.getDriverId(), DriverStatus.BUSY));
        if (CollUtil.isEmpty(position) || (ObjectUtil.isEmpty(position.get(0)) && ObjectUtil.isEmpty(position.get(1)))) throw new ZhixingException(DRIVER_LOCATION_FAIL);
        Point point = position.get(0) != null ? position.get(0) : position.get(1);

        // 调用地图服务，对司机位置到起点进行路线规划
        RoutePlanningVO routePlanningVO = mapClient.routePlanning(new RoutePlanningDTO(BigDecimal.valueOf(point.getX()).setScale(6, RoundingMode.HALF_UP),
                BigDecimal.valueOf(point.getY()).setScale(6, RoundingMode.HALF_UP), orderReceiveInfo.getStartLongitude(), orderReceiveInfo.getStartLatitude())).getData();
        DriverReceiveOrderVO driverReceiveOrderVO = BeanUtil.copyProperties(orderReceiveInfo, DriverReceiveOrderVO.class);
        BeanUtil.copyProperties(routePlanningVO, driverReceiveOrderVO);
        return driverReceiveOrderVO;
    }

    @Override
    public PassengerReceiveOrderVO passengerGetReceiveOrderInfo(Long orderId) {
        // 数据库获取接单信息，缓存获取司机位置信息
        OrderReceiveInfo orderReceiveInfo = orderMapper.getReceiveOrderInfo(orderId);
        List<Point> position = redisTemplate.opsForGeo().position(ZHIXING_DRIVER_LOCATION + orderReceiveInfo.getCityCode(),
                new DriverInfo(orderReceiveInfo.getDriverId(), DriverStatus.IDLE), new DriverInfo(orderReceiveInfo.getDriverId(), DriverStatus.BUSY));
        if (CollUtil.isEmpty(position) || (ObjectUtil.isEmpty(position.get(0)) && ObjectUtil.isEmpty(position.get(1)))) throw new ZhixingException(DRIVER_LOCATION_FAIL);
        Point point = position.get(0) != null ? position.get(0) : position.get(1);

        // 调用地图服务，对司机位置到起点进行路线规划
        PassengerReceiveOrderVO passengerReceiveOrderVO = BeanUtil.copyProperties(orderReceiveInfo, PassengerReceiveOrderVO.class);
        UserInfo userInfo = UserContext.getUserInfo();
        CompletableFuture<RoutePlanningVO> routeFuture = CompletableFuture.supplyAsync(() -> {
            UserContext.setUserInfo(userInfo);
            return mapClient.routePlanning(new RoutePlanningDTO(BigDecimal.valueOf(point.getX()).setScale(6, RoundingMode.HALF_UP),
                    BigDecimal.valueOf(point.getY()).setScale(6, RoundingMode.HALF_UP),
                    orderReceiveInfo.getStartLongitude(), orderReceiveInfo.getStartLatitude())).getData();
        });
        CompletableFuture<DriverInfoVO> driverFuture = CompletableFuture.supplyAsync(() -> {
            UserContext.setUserInfo(userInfo);
            return userClient.getDriverInfo(orderReceiveInfo.getDriverId()).getData();
        });
        RoutePlanningVO routePlanningVO = routeFuture.join();
        DriverInfoVO driverInfoVO = driverFuture.join();
        if (ObjectUtil.isEmpty(routePlanningVO)) throw new ZhixingException(ROUTE_PLANNING_FAIL);
        if (ObjectUtil.isEmpty(driverInfoVO)) throw new ZhixingException(DRIVER_INFO_FAIL);
        BeanUtil.copyProperties(routePlanningVO, passengerReceiveOrderVO);
        BeanUtil.copyProperties(driverInfoVO, passengerReceiveOrderVO);
        passengerReceiveOrderVO.setDriverName(driverInfoVO.getDriverName().charAt(0) + SHIFU);
        return passengerReceiveOrderVO;
    }

    @Override
    public void startService(Long orderId, String tailNumber) {
        // 查询数据库检查订单状态和尾号
        OrderReceiveInfo orderReceiveInfo = orderMapper.getReceiveOrderInfo(orderId);
        if (orderReceiveInfo.getOrderStatus() != OrderStatus.RECEIVE) throw new ZhixingException(ORDER_STATUS_ERROR);
        if (!tailNumber.equals(orderReceiveInfo.getOrderNumber().substring(orderReceiveInfo.getOrderNumber().length() - 4))) throw new ZhixingException(TAIL_NUMBER_ERROR);
        List<Point> position = redisTemplate.opsForGeo().position(ZHIXING_DRIVER_LOCATION + orderReceiveInfo.getCityCode(),
                new DriverInfo(orderReceiveInfo.getDriverId(), DriverStatus.BUSY));
        if (CollUtil.isEmpty(position) || ObjectUtil.isEmpty(position.get(0))) throw new ZhixingException(DRIVER_LOCATION_FAIL);

        // 判断司机距离起点是否在500米内
        double distance = LocationUtil.calculateDistance(orderReceiveInfo.getStartLongitude().doubleValue(),
                orderReceiveInfo.getStartLatitude().doubleValue(), position.get(0).getX(), position.get(0).getY());
        if (distance > 500) throw new ZhixingException(DISTANCE_START_DISTANT);
        LambdaUpdateWrapper<Order> luw = new LambdaUpdateWrapper<Order>().eq(Order::getId, orderId).eq(Order::getOrderStatus, OrderStatus.RECEIVE)
                .set(Order::getOrderStatus, OrderStatus.PERFORM).set(Order::getStartTime, LocalDateTime.now());
        int i = orderMapper.update(luw);

        // 通知乘客开始服务
        if (i == 1) {
            String instanceId = (String) redisTemplate.opsForHash().get(ZHIXING_ORDER_WEBSOCKET, orderId);
            if (instanceId != null) kafkaTemplate.send(ZHIXING_SEND_PASSENGER + instanceId, new OrderStatusVO(orderId, OrderStatus.PERFORM));
        }
    }

    @Override
    public OrderStartInfoVO getOrderStartInfo(Long orderId) {
        // 查询数据库获取订单信息
        Order order = orderMapper.selectById(orderId);
        if (ObjectUtil.isEmpty(order)) throw new ZhixingException(ORDER_NOT_EXIST);
        if (order.getOrderStatus() != OrderStatus.PERFORM) throw new ZhixingException(ORDER_STATUS_ERROR);
        return BeanUtil.copyProperties(order, OrderStartInfoVO.class);
    }

    @Override
    @Transactional
    public void arriveEnd(Long orderId) {
        // 查询数据库获取订单信息
        Order order = orderMapper.selectById(orderId);
        if (ObjectUtil.isEmpty(order)) throw new ZhixingException(ORDER_NOT_EXIST);
        if (order.getOrderStatus() != OrderStatus.PERFORM) throw new ZhixingException(ORDER_STATUS_ERROR);

        // 添加订单实际信息
        order.setRealPolyline(order.getEstimatePolyline());
        Random random = new Random();
        if (order.getEstimateDistance().compareTo(new BigDecimal(3)) > 0) {
            double randomDistance = Math.round(10 * (-0.3 + random.nextDouble() * 0.6)) / 10.0;
            order.setRealDistance(order.getEstimateDistance().add(new BigDecimal(randomDistance)).setScale(1, RoundingMode.HALF_UP));
        }
        else order.setRealDistance(order.getEstimateDistance());
        order.setRealDuration(order.getEstimateDuration() > 5 ? order.getEstimateDuration() + random.nextInt(5) - 2 : order.getEstimateDuration());

        // 添加此订单的费用规则，并更新订单
        FeeRuleVO feeRuleVO = getFeeRule(new FeeRuleDTO(order.getStartTime().toLocalTime(), order.getRealDistance()));
        FeeRule feeRule = BeanUtil.copyProperties(feeRuleVO, FeeRule.class);
        feeRule.setOrderId(orderId);
        feeRuleMapper.insert(feeRule);
        order.setRealFee(feeRuleVO.getTotalFee());
        order.setOrderStatus(OrderStatus.PAYMENT);
        order.setEndTime(LocalDateTime.now());
        int i = orderMapper.updateById(order);

        // 通知乘客到达终点，支付订单
        if (i == 1) {
            String instanceId = (String) redisTemplate.opsForHash().get(ZHIXING_ORDER_WEBSOCKET, orderId);
            if (instanceId != null) kafkaTemplate.send(ZHIXING_SEND_PASSENGER + instanceId, new OrderStatusVO(orderId, OrderStatus.PAYMENT));
        }
    }

    @Override
    public OrderPayInfoVO getOrderPayInfo(Long orderId) {
        // 查询数据库获取订单信息
        OrderPayInfoVO orderPayInfoVO = orderMapper.getOrderPayInfo(orderId);
        if (ObjectUtil.isEmpty(orderPayInfoVO)) throw new ZhixingException(ORDER_NOT_EXIST);
        if (orderPayInfoVO.getOrderStatus() != OrderStatus.PAYMENT) throw new ZhixingException(ORDER_STATUS_ERROR);
        return orderPayInfoVO;
    }

    @Override
    public FeeRuleVO getOrderFeeRule(Long orderId) {
        // 查询数据库获取订单费用规则
        LambdaQueryWrapper<FeeRule> lqw = new LambdaQueryWrapper<FeeRule>().eq(FeeRule::getOrderId, orderId);
        FeeRule feeRule = feeRuleMapper.selectOne(lqw);
        if (ObjectUtil.isEmpty(feeRule)) throw new ZhixingException(ORDER_NOT_EXIST);
        return BeanUtil.copyProperties(feeRule, FeeRuleVO.class);
    }

    @Override
    @GlobalTransactional
    public void payOrder(Long orderId, Integer couponId, Integer userId) {
        // 查询订单实际费用
        BigDecimal realFee = orderMapper.getRealFee(orderId, userId, OrderStatus.PAYMENT);
        if (ObjectUtil.isEmpty(realFee)) throw new ZhixingException(ORDER_NOT_EXIST);

        // 是否使用优惠券并计算实际支付
        BigDecimal realPayment;
        if (ObjectUtil.isNotEmpty(couponId)) {
            CouponUseInfo couponUseInfo = rewardclient.getCouponUseInfoById(couponId).getData();
            if (ObjectUtil.isEmpty(couponUseInfo)) throw new ZhixingException(COUPON_NOT_EXIST);
            if (couponUseInfo.getConditionAmount().compareTo(realFee) > 0) throw new ZhixingException(CONDITION_AMOUNT_DISSATISFY);
            if (couponUseInfo.getCouponType() == CouponType.CASH_COUPON) realPayment = realFee.subtract(couponUseInfo.getAmount()).setScale(2, RoundingMode.HALF_UP);
            else realPayment = realFee.multiply(couponUseInfo.getDiscount()).setScale(2, RoundingMode.HALF_UP);
        }
        else realPayment = realFee;

        // 支付订单和使用优惠券
        UserInfo userInfo = UserContext.getUserInfo();
        CompletableFuture<Integer> payFuture = CompletableFuture.supplyAsync(() -> {
            UserContext.setUserInfo(userInfo);
            return payClient.payOrder(realPayment).getCode();
        });
        CompletableFuture<Integer> couponFuture = CompletableFuture.supplyAsync(() -> {
            UserContext.setUserInfo(userInfo);
            return ObjectUtil.isEmpty(couponId) ? OK.getCode() : rewardclient.useCoupon(couponId).getCode();
        });
        Integer payCode = payFuture.join();
        Integer couponCode = couponFuture.join();
        if (payCode != OK.getCode()) throw new ZhixingException(payCode == BALANCE_NOT_SUFFICIENT.getCode() ? BALANCE_NOT_SUFFICIENT : ORDER_PAYMENT_FAIL);
        if (couponCode != OK.getCode()) throw new ZhixingException(COUPON_USE_FAIL);

        // 更新订单状态
        LambdaUpdateWrapper<Order> luw = new LambdaUpdateWrapper<Order>().eq(Order::getId, orderId)
                .set(ObjectUtil.isNotEmpty(couponId), Order::getCouponId, couponId).set(Order::getRealPayment, realPayment)
                .set(Order::getOrderStatus, OrderStatus.COMPLETE);
        if (orderMapper.update(luw) == 0) throw new ZhixingException(ORDER_PAYMENT_FAIL);

        // 司机打款
        kafkaTemplate.send(ZHIXING_ORDER_COMPLETE, orderId);
    }

    @Override
    @GlobalTransactional
    public void driverRemit(Long orderId) {
        // 查询订单完成信息和司机当天订单量
        OrderCompleteInfo orderCompleteInfo = orderMapper.getOrderCompleteInfo(orderId, OrderStatus.COMPLETE);
        if (ObjectUtil.isEmpty(orderCompleteInfo)) throw new ZhixingException(ORDER_NOT_EXIST);
        Integer orderCount = orderMapper.getTodayOrderCount(orderCompleteInfo.getDriverId(), LocalDate.now(), OrderStatus.COMPLETE);

        // 添加此订单的抽成规则，并更新订单
        CommissionRuleVO commissionRuleVO = getCommissionRule(new CommissionRuleDTO(orderCompleteInfo.getStartTime().toLocalTime(), orderCompleteInfo.getRealDistance(), orderCount));
        CommissionRule commissionRule = BeanUtil.copyProperties(commissionRuleVO, CommissionRule.class);
        commissionRule.setOrderId(orderId);
        commissionRuleMapper.insert(commissionRule);
        BigDecimal realIncome = orderCompleteInfo.getRealPayment().multiply(new BigDecimal(1).subtract(commissionRuleVO.getTotalCommission())).setScale(2, RoundingMode.HALF_UP);
        LambdaUpdateWrapper<Order> luw = new LambdaUpdateWrapper<Order>().eq(Order::getId, orderId).set(Order::getRealIncome, realIncome);
        if (orderMapper.update(luw) == 0) throw new ZhixingException(ORDER_REMIT_FAIL);

        // 司机打款
        UserContext.setUserInfo(new UserInfo(orderCompleteInfo.getUserId(), Role.PASSENGER));
        Res<Integer> userRes = userClient.getUserIdByDriverId(orderCompleteInfo.getDriverId());
        if (userRes.getCode() != OK.getCode() || ObjectUtil.isEmpty(userRes.getData())) throw new ZhixingException(DRIVER_NOT_EXIST);
        UserContext.setUserInfo(new UserInfo(userRes.getData(), Role.DRIVER));
        Res<Void> voidRes = payClient.driverRemit(realIncome);
        if (voidRes.getCode() != OK.getCode()) throw new ZhixingException(ORDER_REMIT_FAIL);
    }
}
